﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Configuration;
using System.Windows;
using System.Xml.Linq;
using System.IO;
using System.Windows.Threading;

namespace SoftWareBoot
{
    /// <summary>
    /// App.xaml 的交互逻辑
    /// </summary>
    public partial class App : Application
    {
        private readonly static DispatcherOperationCallback exitFrameCallback = ExitFrame;

        const string CONST_PATH = "BootConfig.xml";

        const string CONST_PROGRAMCONFIG_PATH = @"Bin\update.xml";

        private const string CONST_BINDING_FILE = "boot.config";

        internal static NetTcpBinding getBinding()
        {
            if (!File.Exists(CONST_BINDING_FILE)) throw new Exception("没有找到升级协议配置文件.");

            var configMap = new ExeConfigurationFileMap {ExeConfigFilename = CONST_BINDING_FILE};

            Configuration config = ConfigurationManager.OpenMappedExeConfiguration(configMap,
                                                                                  ConfigurationUserLevel
                                                                                      .None);
            BindingsSection elementBinding = BindingsSection.GetSection(config);

            if (elementBinding.NetTcpBinding.Bindings.Count == 0) return null;

            var binding = new NetTcpBinding();

            elementBinding.NetTcpBinding.Bindings.Cast<NetTcpBindingElement>().First().ApplyConfiguration(binding);

            return binding;
        }



        protected override void OnStartup(StartupEventArgs e)
        {

            AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;

            string serviceuri, prjname, startProgramPath;

            serviceuri = prjname = startProgramPath = string.Empty;


            if (File.Exists(CONST_PATH))
            {
                try
                {
                    XDocument xDoc = new XDocument();

                    xDoc = XDocument.Load(CONST_PATH);

                    XElement element = xDoc.Element("AutoUpdater");

                    serviceuri = element.Descendants()
                                        .Where(xe => xe.Attribute("Name").Value.ToLower() == "uri")
                                        .Select<XElement, string>(xe => xe.Attribute("Value").Value).First().Trim();        //获取服务地址

                    prjname = element.Descendants()
                                        .Where(xe => xe.Attribute("Name").Value.ToLower() == "project")
                                        .Select<XElement, string>(xe => xe.Attribute("Value").Value).First().Trim();        //获取项目名称
                    startProgramPath = element.Descendants()
                                        .Where(xe => xe.Attribute("Name").Value.ToLower() == "startprogrampath")
                                        .Select<XElement, string>(xe => xe.Attribute("Value").Value).First().Trim();        //获取系统启动程序路径
                }
                catch (Exception)
                {
                }
            }

            if (serviceuri == string.Empty || prjname == string.Empty)          //如果路径和名称有一项配置项为空，都要启动自动升级配置窗体
            {
                if (!ShowConfigWindow(ref serviceuri, ref prjname))
                {
                    Shutdown();
                    return;
                }
            }

            try
            {
                string version, verdate, localversion, localverdate;

                AutoUpdateService.AutoUpdateClient Client = new AutoUpdateService.AutoUpdateClient(getBinding(), new EndpointAddress(serviceuri));

                //Client.Endpoint.Address = new System.ServiceModel.EndpointAddress(serviceuri);

                if (Client.GetProjectVersion(out version, out verdate, prjname))            //如果访问服务失败，则直接退出
                {
                    try
                    {
                        XDocument xDoc = new XDocument();

                        xDoc = XDocument.Load(string.Format(@"{0}\{1}", System.Environment.CurrentDirectory, CONST_PROGRAMCONFIG_PATH));
                        localversion = xDoc.Element("AutoUpdater").Element("Version").Attribute("Num").Value;
                        localverdate = xDoc.Element("AutoUpdater").Element("UpdateTime").Attribute("Date").Value;
                    }
                    catch
                    {
                        localverdate = "";
                        localversion = "";
                    }

                    if (localverdate != verdate || startProgramPath == string.Empty || !File.Exists(startProgramPath))
                    {   //如果当前版本不等于服务器版本，或者启动程序为空，或者找不到启动程序，就需要启动自动升级操作窗体
                        string startpath = ShowAutoUpdateWindow(Client, prjname, version, verdate, localversion, localverdate);

                        if (startpath != null && startpath != string.Empty)
                        {
                            startProgramPath = string.Format(@"{0}\Bin\{1}", System.Environment.CurrentDirectory, startpath);           //系统启动程序路径更新成最新返回的数据

                            XDocument xDoc = new XDocument();

                            xDoc = XDocument.Load(CONST_PATH);
                            try
                            {
                                xDoc.Element("AutoUpdater").Descendants().Where(x => x.Attribute("Name").Value == "StartProgramPath").First().Attribute("Value").Value = startProgramPath;
                            }
                            catch
                            {
                                xDoc.Element("AutoUpdater").Add(new XElement("Item",
                                                                            new XAttribute("Name", "StartProgramPath"),
                                                                            new XAttribute("Value", startProgramPath)));
                            }
                            xDoc.Save(CONST_PATH);
                        }
                    }
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show(String.Format("自动升级模块启动失败\r\n失败原因：{0}", ex.Message), "升级故障", MessageBoxButton.OK, MessageBoxImage.Error);
            }

            if (startProgramPath != "" && File.Exists(startProgramPath))
            {
                try
                {

                    System.Diagnostics.ProcessStartInfo ps = new System.Diagnostics.ProcessStartInfo(startProgramPath) { WorkingDirectory = (new FileInfo(startProgramPath)).DirectoryName };

                    System.Diagnostics.Process.Start(ps);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(String.Format("项目程序启动失败...\r\n失败原因：{0}", ex.Message), "程序启动失败", MessageBoxButton.OK, MessageBoxImage.Exclamation);
                }
            }


            Shutdown();
        }

        void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            MessageBox.Show(e.ExceptionObject.ToString());
        }

        private static bool ShowConfigWindow(ref string OutUri, ref string OutPrjName)
        {

            Window_StartSetting w = new Window_StartSetting();

            if (!(bool)w.ShowDialog()) return false;

            OutUri = w.ServiceUri;

            OutPrjName = w.ProjectName;

            XDocument xDoc = new XDocument();

            xDoc.Add(new XElement("AutoUpdater",
                                            new XElement("Item",
                                                                new XAttribute("Name", "Uri"),
                                                                new XAttribute("Value", OutUri)),
                                             new XElement("Item",
                                                                new XAttribute("Name", "Project"),
                                                                new XAttribute("Value", OutPrjName)),
                                             new XElement("Item",
                                                                new XAttribute("Name", "StartProgramPath"),
                                                                new XAttribute("Value", ""))));

            xDoc.Save(CONST_PATH);

            return true;

        }


        public static void DoEvents()
        {
            DispatcherFrame nestedFrame = new DispatcherFrame();

            DispatcherOperation exitOperation = Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, exitFrameCallback, nestedFrame);

            Dispatcher.PushFrame(nestedFrame);

            if (exitOperation.Status != DispatcherOperationStatus.Completed)
            {
                exitOperation.Abort();
            }
        }

        private static Object ExitFrame(Object state)

        {

            DispatcherFrame frame = state as DispatcherFrame;

            frame.Continue = false;

            return null;

        }


        /// <summary>
        /// 显示升级操作UI
        /// </summary>
        /// <param name="client"></param>
        /// <param name="newversion"></param>
        /// <param name="newverdate"></param>
        /// <param name="localversion"></param>
        /// <param name="localverdate"></param>
        private static string ShowAutoUpdateWindow(AutoUpdateService.AutoUpdateClient client, string prjname, string newversion, string newverdate, string localversion, string localverdate)
        {

            Window_AutoUpdate windowAutoUpdate = new Window_AutoUpdate() { ProjectName = prjname };

            windowAutoUpdate.SetData(client, newversion, newverdate, localversion, localverdate);

            windowAutoUpdate.ShowDialog();

            return windowAutoUpdate.StartProgramPath;

        }
    }
}
